#include "ohos_init.h"
#include "los_task.h"
#include "los_sem.h"
#include "los_swtmr.h"
#include <string.h>
#include <unistd.h>
#include "lcd.h"
#include "e53_me_Fir.h"
#include "e53_medical_electrocardiogram.h"
#include "e53_heart_rate_detection.h"
#include "e53_temperature_measurement.h"
#include "picture.h"
#include "com_msg.h"
#include "swtmr.h"
#include "e53_com.h"

void e53_em_thread_delete(void);




#define asw16(x)                                              \
    ((uint16_t)((((uint16_t)((x)[0]) & (uint16_t)0x00ffU) << 8) | \
                (((uint16_t)((x)[1]) & (uint16_t)0xff00U) >> 8)))



#define sw16(x)                                              \
    ((uint16_t)((((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \
                (((uint16_t)(x) & (uint16_t)0xff00U) >> 8)))

#define PER_YLINE_VAL        53                                      // 显示百分比   刷屏来不及适当减小比例
#define SAMPLING_FREQ        250                                     // 数据采样频率
#define DRAW_NUMBER          320                                     // 绘制点数X轴
#define YLINE_MAX            240                                     // y轴最大值
#define MOVE_STEP            32                                      // 移动步距  必须能被DRAW_NUMBER整除
#define DISPLAY_HANDLE_TIME  (DRAW_NUMBER*1000000/SAMPLING_FREQ)     // 一帧显示时间                                   
#define MULTIPLE_MIN         20                                      // 最小倍数
#define HRD_MIN_VAL          20                                      // 心率测量最小值 （理论值实际会比此值大一些）
#define HRD_MIN_CAL_POINT    (60*SAMPLING_FREQ/HRD_MIN_VAL+50)       // 心率计算点数最小值
#define DELAY_SAVE           5000                                    // 延时预留时间

#define PER_YLINE(x)         (YLINE_MAX * (x) / 100)                 // y轴显示百分比实际值
#define YLENE_START(x)       ((YLINE_MAX - PER_YLINE(x)) / 2)        // y轴起始显示位置
#define MEM_YLINE            (PER_YLINE(PER_YLINE_VAL)+1)            // 申请内存行数 必须大于(PER_YLINE(PER_YLINE_VAL))    240*0.7=168
#define HYP                  (48)                                    // 图片高度
#define HYT                  (32)                                    // 标题高度
#define HYV                  (32)                                    // 心率值高度
#define HYP_T                (HYP+HYT)
#define HYP_T_V              (HYP+HYT+HYV)

#define YLINE_REVERSAL                                               // 波形反转
#define XLINE_REVERSAL                                               // 左移还是右移

#ifdef  YLINE_REVERSAL
#define SY1                  (YLINE_MAX-HYP_T_V)
#define SY2                  (YLINE_MAX-HYP_T)
#define Y_START1             (YLINE_MAX - YLENE_START(PER_YLINE_VAL)*2)                      // 补点默认值
#define Y_VAL1(x, min, mul)  (YLINE_MAX - ((x - min) / mul + YLENE_START(PER_YLINE_VAL)*2))  // 反转y轴值计算
#define Y_VAL(x, min, mul)   (YLINE_MAX - ((x - min) / mul + YLENE_START(PER_YLINE_VAL)-23)) // 反转y轴值计算
#else
#define SY1                  HYP_T_V
#define SY2                  HYP_T
#define Y_START1             (YLENE_START(PER_YLINE_VAL)*2)                    // 补点默认值
#define Y_VAL1(x, min, mul)  ((x - min) / mul)                                 // y轴值计算
#define Y_VAL(x, min, mul)   ((x - min) / mul + YLENE_START(PER_YLINE_VAL)+23) // y轴值计算
#endif


#ifdef XLINE_REVERSAL
#define X_START              (DRAW_NUMBER-MOVE_STEP)                           // X轴起始位置
#define X_VAL(x)             (DRAW_NUMBER-(x)-1)    
#define POINT_DATA_DIR       (X_START)                                         // 补点x值
#define WAVE_DATA_DIR(a)     (X_START+(a))                                     // 波形x值
#define X_MEM_MOVE_SRC       MOVE_STEP                                         // 内存移动源位置
#define X_MEM_MOVE_DST       0                                                 // 内存移动目标位置
#else
#define X_START              0
#define X_VAL(x)             (x)    
#define POINT_DATA_DIR       (MOVE_STEP)                                       // 补点x值
#define WAVE_DATA_DIR(a)     (MOVE_STEP-(a)-1)                                 // 波形x值
#define X_MEM_MOVE_SRC       0                                                 // 内存移动源位置
#define X_MEM_MOVE_DST       MOVE_STEP                                         // 内存移动目标位置
#endif
#define DATA_DIR(a, b)       ((a)+(b)*MOVE_STEP)                               // 原始数据位置
#define X_MOVE_END           (X_START+MOVE_STEP)                               // X轴移动结束位置

#define FIFO_MAXSIZE         10 // 队列缓存数

typedef float float_hrd[DRAW_NUMBER];
typedef uint32_t uint32_hrd[DRAW_NUMBER];
typedef uint16_t uint16_hrd[DRAW_NUMBER];

/* 定义先进先出队列  缓存原始数据*/
typedef struct
{
    UINT32    sem;
    uint16_t  offset_read;
    uint16_t  offset_write;
    float_hrd buffer[FIFO_MAXSIZE];
} hrdfifo_s;

//原始数据缓存fifo
static hrdfifo_s m_fifo_hrd =
{
    .sem          = 0,
    .offset_read  = 0,
    .offset_write = 0,
    .buffer       = {{0}},
};

static inline void FifoInitHrd(hrdfifo_s *fifo)
{
    fifo->offset_read = fifo->offset_write = 0;
    // if (LOS_SemCreate(1, &fifo->sem) != LOS_OK)
    // {
    //     printf("Falied to create Semaphore\n");
    // }
}

static inline void FifoPutHrd(hrdfifo_s *fifo, float_hrd *hrd)
{
    // if (LOS_SemPend(fifo->sem, 2) == LOS_OK)
    {
        memcpy(fifo->buffer[fifo->offset_write], hrd, sizeof(float_hrd));
        fifo->offset_write = (fifo->offset_write + 1) % FIFO_MAXSIZE;
        // LOS_SemPost(fifo->sem);
    }
}

static inline uint16_t FifoGetHrd(hrdfifo_s *fifo, float_hrd *hrd)
{
    // if (LOS_SemPend(fifo->sem, 2) == LOS_OK)
    {
        if (fifo->offset_read == fifo->offset_write)
        {
            // LOS_SemPost(fifo->sem);
            return 0;
        }

        memcpy(hrd, fifo->buffer[fifo->offset_read], sizeof(float_hrd));
        fifo->offset_read = (fifo->offset_read + 1) % FIFO_MAXSIZE;
        // LOS_SemPost(fifo->sem);
        return 1;
    }
    return 0;
}

//绘制波形所需参数
typedef struct
{
    uint32_t   index;
    uint32_t   multiple;      // 液晶屏显示时波形的衰减倍数动态调整
    uint32_t   min;
    uint32_t   max;
    uint32_hrd Draw_data;     // 绘制波形数据
} wave_param_t;

/* 定义先进先出队列  缓存lcd 显示数据*/
typedef struct
{
    UINT32       sem;
    uint16_t     offset_read;
    uint16_t     offset_write;
    wave_param_t buffer[FIFO_MAXSIZE];
} lcdfifo_s;

// lcd显示数据缓存fifo
static lcdfifo_s m_fifo_hrd_lcd =
{
    .sem          = 0,
    .offset_read  = 0,
    .offset_write = 0,
    .buffer       = {{0}},
};

static inline void FifoInitLcd(lcdfifo_s *fifo)
{
    fifo->offset_read = fifo->offset_write = 0;
    // if (LOS_SemCreate(1, &fifo->sem) != LOS_OK)
    // {
    //     printf("Falied to create Semaphore\n");
    // }
}

static inline void FifoPutLcd(lcdfifo_s *fifo, wave_param_t *data)
{
    // if (LOS_SemPend(fifo->sem, 2) == LOS_OK)
    {
        memcpy(&fifo->buffer[fifo->offset_write], data, sizeof(wave_param_t));
        fifo->offset_write = (fifo->offset_write + 1) % FIFO_MAXSIZE;
        // LOS_SemPost(fifo->sem);
    }
}

static inline uint16_t FifoGetLcd(lcdfifo_s *fifo, wave_param_t *data)
{
    // if (LOS_SemPend(fifo->sem, 2) == LOS_OK)
    {
        if (fifo->offset_read == fifo->offset_write)
        {
            // LOS_SemPost(fifo->sem);
            return 0;
        }

        memcpy(data, &fifo->buffer[fifo->offset_read], sizeof(wave_param_t));
        fifo->offset_read = (fifo->offset_read + 1) % FIFO_MAXSIZE;
        // LOS_SemPost(fifo->sem);
        return 1;
    }
    return 0;
}

typedef enum
{
    TASK_TYPE_MAIN,
    TASK_TYPE_CONTROL,
    TASK_TYPE_LCD,

    TASK_TYPE_MAX,
} task_type_e;

typedef struct
{
    uint8_t y1;
    uint8_t y2;
} wave_yline_t;

typedef struct
{
    UINT32           id;
    TSK_INIT_PARAM_S param;
} mytask_t;

typedef struct
{
    uint16_t  point_cnt;
    float     hrd;
} hrd_calc_t;

typedef struct
{
    UINT32          sem_gpio;                   
    mytask_t        task[TASK_TYPE_MAX];
      
    uint16_t        data_index;                 // 接收的数据序号
    uint16_t        back_color;                 // 背景颜色
    uint16_t        line_color[3];
      
    float_hrd       input_data;                 // 输入信号存储的数组
    float_hrd       output_data;                // FIR滤波后的数据
    wave_yline_t    last_yline[DRAW_NUMBER];    // 前一帧y值

    hrdfifo_s      *hrd;                        // 心率缓冲队列
    lcdfifo_s      *hrd_lcd;                    // lcd 显示缓存

    uint16_hrd     *wave;                       // 波形缓存
    uint16_hrd     *wave_background;            // 波形背景

    hrd_calc_t      hrd_calc;                   // 心率计算

    e53_tm_data_t  *tm_data;
    e53_hrd_data_t *hrd_data;
    swtmr_t         swtmr;

} ads1292_t;

ads1292_t m_ads1292 =
{
    .task             = {{0}},

    .data_index       = 0,
    .back_color       = LCD_WHITE,
    .line_color       = {LCD_BLACK, LCD_RED, LCD_BROWN},
    
    .hrd              = &m_fifo_hrd,
    .hrd_lcd          = &m_fifo_hrd_lcd,
    .wave_background  = (uint16_hrd*)gImage_background,

    .hrd_calc         = 
    {
        .point_cnt    = 0,
        .hrd          = 0.0,
    },

    .tm_data          = &g_tm_data,
    .hrd_data         = &g_hrd_data,
    .swtmr = 
    {
        .cnt                    = 0,
        .args                   = NULL,

        .getid_fn               = swtmr_getid,
        .start_fn               = swtmr_start,
        .stop_fn                = swtmr_stop,
        .init_fn                = swtmr_init,
    },
};


void draw_wave(uint32_t *Draw_data, uint32_t multiple, uint32_t min, wave_yline_t *last_yline, uint16_t color) //画出波形
{
    uint16_t i;
    uint_tick ts = 0, td = 0;
    wave_yline_t line;

    if (multiple < MULTIPLE_MIN)
        multiple = MULTIPLE_MIN;
    // else
    //     printf("mul:%lu\n", multiple);

    for (i = 0; i < DRAW_NUMBER - 1; ++i)
    {
        ts = get_current_tick();
        line.y1 = Y_VAL(Draw_data[i], min, multiple);
        line.y2 = Y_VAL(Draw_data[i + 1], min, multiple);

        if (last_yline[i].y1 != line.y1 || last_yline[i].y2 != line.y2)
        {
            if (last_yline[i].y1 != last_yline[i].y2)
                lcd_draw_line(X_VAL(i), last_yline[i].y1, X_VAL(i + 1), last_yline[i].y2, m_ads1292.back_color);
            else
                lcd_draw_point(X_VAL(i), last_yline[i].y1, m_ads1292.back_color);
        }

        if (line.y1 != line.y2)
            lcd_draw_line(X_VAL(i), line.y1, X_VAL(i + 1), line.y2, color);
        else
            lcd_draw_point(X_VAL(i), line.y1, color);

        last_yline[i].y1 = line.y1;
        last_yline[i].y2 = line.y2;

        td = get_time_us(ts);
        if (td < 2100)
        {
            LOS_Msleep(2 - td / 1000);
        }
    }
}

//波形刷新
void wave_fresh(uint16_hrd *wave, uint16_hrd *bg, wave_param_t src, uint16_t color, uint32_t delay_us) //画出波形
{
    static uint8_t last_y = Y_START1;
    uint16_t i, j, n;
    wave_yline_t line = {.y1 = 0, .y2 = 0};

    int dsize = PER_YLINE(PER_YLINE_VAL);
    int sy;
    if(dsize < SY1)
    {
        sy = (SY1-dsize)/2+HYP+HYT;
    }
    else if(dsize < SY2)
    {
        sy = (SY2-dsize)/2+HYP;
    }
    else
    {
        sy = HYP;
    }

    if (src.multiple < MULTIPLE_MIN)
        src.multiple = MULTIPLE_MIN;

    for (n = 0; n < DRAW_NUMBER / MOVE_STEP; ++n)
    {
        for (i = 0; i < MEM_YLINE; ++i)
        { //清背景
            // for (j = X_START; j < X_MOVE_END; ++j)
            // {
            //     wave[i][j] = color;
            // }
            //背景空间大小必须与wave空间一致
            memcpy(&wave[i][X_START], &bg[i][X_START], MOVE_STEP*2);
        }

        //补点
        line.y2 = Y_VAL1(src.Draw_data[DATA_DIR(0, n)], src.min, src.multiple);
        if (last_y != line.y2)
        {
            if (last_y > line.y2)
            {
                for (int y = line.y2; y <= last_y; ++y)
                    wave[y][POINT_DATA_DIR] = color;
            }
            else
            {
                for (int y = last_y; y <= line.y2; ++y)
                    wave[y][POINT_DATA_DIR] = color;
            }
        }
        else
            wave[last_y][POINT_DATA_DIR] = color;

        for (j = 0; j + 1 < MOVE_STEP; ++j)
        { //画图
            line.y1 = Y_VAL1(src.Draw_data[DATA_DIR(j, n)], src.min, src.multiple);
            line.y2 = Y_VAL1(src.Draw_data[DATA_DIR(j+1, n)], src.min, src.multiple);
            // if (line.y1 >= MEM_YLINE || line.y2 >= MEM_YLINE)
            // {
            //     printf("%u y1:%u,y2:%u, min:%lu,mul:%lu, %lu,%lu\n", j, line.y1, line.y2, src.min, src.multiple, src.Draw_data[DATA_DIR(j, n)], src.Draw_data[DATA_DIR(j+1, n)]);
            // }
            if (line.y1 != line.y2)
            {
                if (line.y1 > line.y2)
                {
                    for (int y = line.y2; y < line.y1; ++y)
                        wave[y][WAVE_DATA_DIR(j)] = color;
                }
                else
                {
                    for (int y = line.y1; y < line.y2; ++y)
                        wave[y][WAVE_DATA_DIR(j)] = color;
                }
            }
            else
                wave[line.y1][WAVE_DATA_DIR(j)] = color;
        }
        last_y = line.y2;
        
        lcd_show_picture(0, sy, DRAW_NUMBER, MEM_YLINE, (uint8_t *)wave);
        usleep(delay_us);
        // LOS_Msleep(delay_us/1000);    //均衡移动

        for (int i = 0; i < MEM_YLINE; ++i)
        { //移动内存 预留新数据位置
            memmove(&m_ads1292.wave[i][X_MEM_MOVE_DST], &m_ads1292.wave[i][X_MEM_MOVE_SRC], (DRAW_NUMBER - MOVE_STEP) * 2);
        }
    }
}

#define AVE_COUNT  4
typedef struct 
{
    float val;
    uint32_t cnt;
    float data[AVE_COUNT];
}ave_cal_t;

//快速排序比较大小
int e53_c11_qcomp(const void *a, const void *b)
{
    return *(float*)a>*(float*)b? 1: -1;
}

//计算平均值
float e53_c11_cal_average(float bmp)
{
    static ave_cal_t ave = {0};
    float temp[AVE_COUNT];

    ave.data[ave.cnt%AVE_COUNT] = bmp;
    if(++ave.cnt < AVE_COUNT) return bmp;

    for(int i = 0; i < AVE_COUNT; ++i)
    {
        temp[i] = ave.data[i];
    }
    qsort(temp, AVE_COUNT, 4, e53_c11_qcomp);
    ave.val = 0;
    for(int i = 1; i < AVE_COUNT-1; ++i)
    {
        ave.val += temp[i];
    }
    // printf("ave:%f,%f\n", ave.val,ave.val/(AVE_COUNT-2));
    
    return (ave.val/(AVE_COUNT-2));
}

//计算差异值
float e53_c11_cal_dif(float bmp, uint32_t dif)
{
    static float last = 0;
    static int   cnt  = 0; 
    float        ave = e53_c11_cal_average(bmp);

    if(ave > bmp+dif || (bmp > dif && ave < bmp-dif))
    {
        if(++cnt < 2)
        {
            // printf("dif:%f-%f!!!\n\n", ave, last);
            return last;  
        }
         
    } 

    cnt  = 0;
    last = ave;
    return ave;
}


//计算心率
float calc_hrd(wave_param_t *wave , uint16_t *point_cnt)
{
    static float last_BPM  = 0;
    static int   zero_cnt  = 0;
    float        BPM       = 0.0, BPM_pre = 0.0; // 心率
    uint32_t     BPM_LH[3] = {0};         

    // 寻找峰值，并计算心率
    for (int j = 0; j < DRAW_NUMBER; j++)
    {
        BPM_LH[0] = BPM_LH[1];
        BPM_LH[1] = BPM_LH[2];
        BPM_LH[2] = wave->Draw_data[j];
        if ((BPM_LH[0] < BPM_LH[1]) & (BPM_LH[1] > BPM_LH[2]) & ((wave->max-wave->min) > 2000) & (BPM_LH[1] > wave->max - (wave->max-wave->min) / 4))
        {
            BPM = ((*point_cnt + 1 + j - DRAW_NUMBER) * 4);
            if(BPM < 0) continue;
            BPM = (float)60000.0 / BPM;
            if (BPM > 0)
                BPM_pre = BPM;

            if (BPM < 0)
                BPM = BPM_pre;

            // printf("B:%5.1f, p:%3u,j:%3d,%4u,%4u ,max:%5u, %5u, [%6u,%6u,%6u]\r\n", (float)BPM, *point_cnt, j, (*point_cnt + j - DRAW_NUMBER), 
            // (*point_cnt + j - DRAW_NUMBER)*4, wave->max, wave->max - (wave->max-wave->min)/4, BPM_LH[0], BPM_LH[1], BPM_LH[2]);
            if (BPM > 0 && BPM < 210)
            {
                last_BPM = BPM;
            }
            *point_cnt = DRAW_NUMBER - j - 1;
        }
        else if (*point_cnt > HRD_MIN_CAL_POINT)
        {
            BPM = 0;
            *point_cnt = 0;
        }
    }

    if(BPM == 0 && last_BPM != 0 && ++zero_cnt < 6)
    {
        BPM = last_BPM;
    }
    else if(zero_cnt >= 6)
    {
        zero_cnt = 0;
        last_BPM = 0;
    }

    if(!(BPM >= 0 && BPM < 210))
    {
        BPM = last_BPM;
    }
    BPM = e53_c11_cal_dif(BPM, 5);
    return (BPM);
}

void Gpio_isr()
{
    LOS_SemPost(m_ads1292.sem_gpio);
}

void control_thread(void *args)
{
    TASK_PROCESS_START_LOG();
    uint32_t ch2_data      = 0;
    uint8_t  read_data[9]  = {0}; //读取心率的原始数据
    uint8_t  write_data[9] = {0};

    LOS_SemPend(m_ads1292.sem_gpio, LOS_WAIT_FOREVER);

    while (1)
    {
        LOS_SemPend(m_ads1292.sem_gpio, LOS_WAIT_FOREVER);
        SPI1_ReadWriteNByte(write_data, read_data, 9);
        ch2_data  = 0;
        ch2_data |= (uint32_t)read_data[6] << 16;
        ch2_data |= (uint32_t)read_data[7] << 8;
        ch2_data |= (uint32_t)read_data[8] << 0;
        m_ads1292.input_data[m_ads1292.data_index] = ch2_data ^ 0x800000;
        m_ads1292.data_index++;
        m_ads1292.hrd_calc.point_cnt++;
        if (m_ads1292.data_index >= DRAW_NUMBER)
        {
            m_ads1292.data_index = 0;
            FifoPutHrd(m_ads1292.hrd, &m_ads1292.input_data);
        }
    }
}

void ADS1292_thread(void *args)
{
    TASK_PROCESS_START_LOG();
    bool         init       = true;
    uint16_t     j          = 0;
    float_hrd    input_data = {0};
    wave_param_t wave       = {0};

    while (1)
    {
        if (FifoGetHrd(m_ads1292.hrd, &input_data) == 1)
        {
            // memcpy(m_ads1292.output_data, input_data, 4*DRAW_NUMBER);    //没有数字滤波
            e53_me_process(input_data, m_ads1292.output_data, DRAW_NUMBER); //数字滤波，滤波仍存在问题
            if (init)
            { //第一帧不显示
                init = false;
                continue;
            }

            wave.min = 0xffffffff;
            wave.max = 0;
            for (j = 0; j < DRAW_NUMBER; j++)
            {
                wave.Draw_data[j] = (uint32_t)m_ads1292.output_data[j];
                if (wave.min > wave.Draw_data[j])
                    wave.min = wave.Draw_data[j];
                if (wave.max < wave.Draw_data[j])
                    wave.max = wave.Draw_data[j];
            }
            wave.multiple = (wave.max - wave.min) / PER_YLINE(PER_YLINE_VAL) + 3; //除数必须小于波形Y轴对应LCD像素点（为保留余量略小于LCD像素点）
            ++wave.index; 
            // printf("index:%d,min:%d,max:%d,dif:%d,mul:%d\n\n", wave.index, wave.min, wave.max, (wave.max - wave.min), wave.multiple);
            FifoPutLcd(m_ads1292.hrd_lcd, &wave);
        }
        LOS_Msleep(100);
    }
}

static lcd_param_t lcd = {.dir = 0, .f_color = LCD_LBBLUE, .b_color = LCD_WHITE, .f_size = 32, .start_line = IMAGE_H_SIEZ};

/***************************************************************
* 函数名称: lcd_reset
* 说    明: lcd显示复位
* 参    数: lcd_param_t lcd
* 返 回 值: 无
***************************************************************/
static void lcd_reset(lcd_param_t lcd)
{
    lcd_fill(0, 0, lcd.w, lcd.h, lcd.b_color);
    // lcd_show_picture((lcd.w-IMAGE_W_SIEZ)/2, 0, IMAGE_W_SIEZ, IMAGE_H_SIEZ, gImage_lingzhi);
    lcd_show_picture(65, 0, 190, 38, gImage_EurAsiaUni);
    lcd_draw_line(0, 40, 320, 40, lcd.f_color);
}

/***************************************************************
* 函数名称: lcd_welcome
* 说    明: lcd显示欢迎界面
* 参    数: lcd_param_t lcd
* 返 回 值: 无
***************************************************************/
static void lcd_welcome(lcd_param_t lcd)
{
    static int init = 0;

    lcd_reset(lcd);
    Printf_Lcd(0, lcd.start_line+lcd.f_size*0, lcd.f_color, lcd.b_color, lcd.f_size, E_LCD_SCREEN_ALIGN_MID_NOP, "欢迎使用");
    int len = get_str_size("OpenHarmony", lcd.f_size);
    if(init == 0)
    {
        lcd_left_move(lcd.w-len, LCD_LEFT_MOVE_EDN(lcd.w, "OpenHarmony", lcd.f_size), lcd.start_line+lcd.f_size*1, lcd.f_color, lcd.b_color, lcd.f_size, len, "OpenHarmony"); 
        init =1;
    }
    else 
    {
        Printf_Lcd(0, lcd.start_line+lcd.f_size*1, lcd.f_color, lcd.b_color, lcd.f_size, E_LCD_SCREEN_ALIGN_MID_NOP, "OpenHarmony");
    }
    lcd_right_move(0, LCD_RIGHT_MOVE_EDN(lcd.w,"医疗心电图", lcd.f_size), lcd.start_line+lcd.f_size*2, lcd.f_color, lcd.b_color, lcd.f_size, "医疗心电图");
    LOS_Msleep(1000);
    lcd_reset(lcd);
    lcd_show_picture(0, (SY1-PER_YLINE(PER_YLINE_VAL))/2+HYP+HYT, DRAW_NUMBER, MEM_YLINE, (uint8_t *)gImage_background);

}
/***************************************************************
* 函数名称: display_init
* 说    明: lcd显示初始化
* 参    数: lcd_param_t *lcd, char *name
* 返 回 值: 无
***************************************************************/
static void display_init(lcd_param_t *lcd, char *name)
{    
    printf("\n\n%s\n", __FUNCTION__);
    lcd->w = g_lcd_size.w;
    lcd->h = g_lcd_size.h;
    lcd_welcome(*lcd);
    Printf_Lcd(0, lcd->start_line+lcd->f_size*0, lcd->f_color, lcd->b_color, lcd->f_size, E_LCD_SCREEN_ALIGN_MID_NOP, name);
}


#define ME_SWTMR_FRESH_PERIOD_MS       500
#define STR_ME_SWTMR_FRESH             "me_fresh"

// Printf_Lcd_Line_Move(0, 0, 0, 0, 48, 320, "123456789abcdefghijklmnopqrstuvwxyz一二三四五六七八九十");
void me_fresh_swtimer_callback(uint32_t args)
{
    ads1292_t   *ads1292 = (ads1292_t*)args;
    static int   cnt     = 0;
    static float tmp     = 0;

    if(ads1292->tm_data->temperature > 30) tmp = ads1292->tm_data->temperature;

    Printf_Lcd_Line_Move(0, 216, ads1292->line_color[2], ads1292->back_color, 24, &cnt, "      心电图心率:%5.1f, 心率血氧:%3d, %3d, 红外测温:%.1f℃    ", 
        ads1292->hrd_calc.hrd, ads1292->hrd_data->hrd==-999?0:ads1292->hrd_data->hrd, ads1292->hrd_data->spo2==-999?0:ads1292->hrd_data->spo2, tmp);
}


void me_swtmr_stop(void)
{
    m_ads1292.swtmr.stop_fn(&m_ads1292.swtmr, STR_ME_SWTMR_FRESH);
}

void lcd_thread(void *args)
{
    TASK_PROCESS_START_LOG();
    float  tmp = 0;
    uint_tick ts = 0, td, delay_us = 1000, t = 0;
    uint_tick run_start = 0, run_time = 0, last_run_time = 0;
    wave_param_t w_param;

    display_init(&lcd, "医疗心电图"); 
    
    m_ads1292.swtmr.args = &m_ads1292;
    m_ads1292.swtmr.init_fn(ME_SWTMR_FRESH_PERIOD_MS, me_fresh_swtimer_callback, STR_ME_SWTMR_FRESH, (uint32_t *)&m_ads1292.swtmr);//定时刷新自动检测
    // m_ads1292.swtmr.start_fn(&m_ads1292.swtmr, STR_ME_SWTMR_FRESH);

    static int init = 0;
    if(init == 0)
    {
        m_ads1292.wave = calloc(2, DRAW_NUMBER * MEM_YLINE);
        init = 1;
    }

    if(m_ads1292.wave == NULL)
    {
        return;
    }

    memcpy(m_ads1292.wave, m_ads1292.wave_background, MEM_YLINE * DRAW_NUMBER*2);

    run_start = get_current_tick();
    while (1)
    {
        if (FifoGetLcd(m_ads1292.hrd_lcd, &w_param) == 1)
        {
            ts = get_current_tick();
            m_ads1292.hrd_calc.hrd = calc_hrd(&w_param, &m_ads1292.hrd_calc.point_cnt);
            {
                msg_smart_medical_report_me_t data = {0};
                data.hrd = m_ads1292.hrd_calc.hrd;
                memcpy(data.hrd_data, w_param.Draw_data, sizeof(data.hrd_data));
                send_e53_data(2, &data);
            }
            Printf_Lcd(2, 224, m_ads1292.line_color[0], m_ads1292.back_color, 16, E_LCD_SCREEN_ALIGN_NONE, "心率:%5.1f ", m_ads1292.hrd_calc.hrd);
            // Printf_Lcd(88, 224, m_ads1292.line_color[!m_ads1292.hrd_data->hrd_flag], m_ads1292.back_color, 16, E_LCD_SCREEN_ALIGN_NONE, "%3d ", m_ads1292.hrd_data->hrd==-999?0:m_ads1292.hrd_data->hrd);
            // Printf_Lcd(132, 224, m_ads1292.line_color[!m_ads1292.hrd_data->spo2_flag], m_ads1292.back_color, 16, E_LCD_SCREEN_ALIGN_NONE, "血氧:%3d  ", m_ads1292.hrd_data->spo2==-999?0:m_ads1292.hrd_data->spo2);

            // if(m_ads1292.tm_data->temperature > 30) tmp = m_ads1292.tm_data->temperature;
            // Printf_Lcd(204, 224, m_ads1292.line_color[m_ads1292.tm_data->flag==2], m_ads1292.back_color, 16, E_LCD_SCREEN_ALIGN_NONE, "温度:%.1f℃", tmp);
            // printf("心率:%5.1f, %3d,血氧:%3d,温度：%.1f, %.1f\r\n", m_ads1292.hrd_calc.hrd, m_ads1292.hrd_data->hrd, m_ads1292.hrd_data->spo2,  tmp, m_ads1292.tm_data->temperature);

            // printf("index:%d,min:%d,max:%d,mul:%d,delay:%llu\n\n", w_param.index, w_param.min, w_param.max, w_param.multiple, delay_us);
            // draw_wave(w_param.Draw_data, w_param.multiple, w_param.min, m_ads1292.last_yline, m_ads1292.line_color[1]);
            wave_fresh(m_ads1292.wave, m_ads1292.wave_background, w_param, sw16(m_ads1292.line_color[1]), delay_us);//刷新时间需要略小于一帧数据产生时间
            td = get_time_us(ts);
            if(td > DISPLAY_HANDLE_TIME)
            {
                t = (td-DISPLAY_HANDLE_TIME)/(DRAW_NUMBER/MOVE_STEP)+DELAY_SAVE;
                delay_us = delay_us > t? delay_us-t: 1000;
            }
            else
            {
                t = (DISPLAY_HANDLE_TIME-td)/(DRAW_NUMBER/MOVE_STEP);
                t = t > DELAY_SAVE? t-DELAY_SAVE: 1000;
                delay_us = t >= (DISPLAY_HANDLE_TIME)/(DRAW_NUMBER/MOVE_STEP)? delay_us: delay_us+t;
            }

            // {
            //     run_time = get_time_us(run_start);
            //     last_run_time = last_run_time == 0? run_time: last_run_time;
            //     printf("runtime"FORMAT_UINT_TICK".%03llus-dif:"FORMAT_UINT_TICK"ms, delay_us:"FORMAT_UINT_TICK"\n", run_time/1000000, (run_time%1000000)/1000, (run_time-last_run_time)/1000, delay_us);
            //     last_run_time = get_time_us(run_start);
            // }
        }
        LOS_Msleep(5);
    }
}


void e53_em_thread_delete(void)
{
    me_swtmr_stop();
    LOS_SemDelete(m_ads1292.sem_gpio);
    LOS_TaskDelete(m_ads1292.task[TASK_TYPE_MAIN].id);
    LOS_TaskDelete(m_ads1292.task[TASK_TYPE_CONTROL].id);
    LOS_TaskDelete(m_ads1292.task[TASK_TYPE_LCD].id);
}


void e53_em_thread(void *args)
{
    LOS_Msleep(300);
    TASK_PROCESS_START_LOG();
    unsigned int ret     = LOS_OK;
    uint32_t    *flag    = (uint32_t *)args;
    ads1292_t   *ads1292 = &m_ads1292;

    FifoInitHrd(m_ads1292.hrd);
    FifoInitLcd(m_ads1292.hrd_lcd);

    ret = LOS_SemCreate(1, &m_ads1292.sem_gpio);
    if (ret != LOS_OK)
    {
        printf("Falied to create Semaphore\n");
        return;
    }

    e53_em_init(*flag);
    create_task(&ads1292->task[TASK_TYPE_LCD].id,       10240, 3,   lcd_thread,                NULL, "lcd_thread");
    create_task(&ads1292->task[TASK_TYPE_MAIN].id,      10240, 6,   ADS1292_thread,            NULL, "ADS1292_thread");
    create_task(&ads1292->task[TASK_TYPE_CONTROL].id,   10240, 1,   control_thread,            NULL, "control_thread");

    while(1)
    {
        LOS_Msleep(100000);
    }
}


/***************************************************************
* 函数名称: e53_me_example
* 说    明: 医疗心电图模块例程
* 参    数: 无
* 返 回 值: 无
***************************************************************/
void e53_me_example()
{
    unsigned int ret = LOS_OK;
    unsigned int thread_id;
    TSK_INIT_PARAM_S task = {0};

    task.pfnTaskEntry = (TSK_ENTRY_FUNC)e53_em_thread;
    task.uwStackSize = 10240;
    task.pcName = "e53_wg_thread";
    task.usTaskPrio = 24;
    ret = LOS_TaskCreate(&thread_id, &task);
    if (ret != LOS_OK)
    {
        printf("Falied to create e53_wm_thread ret:0x%x\n", ret);
        return;
    }
}


// APP_FEATURE_INIT(e53_me_example);
